﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using TV_Agenda_V2.Utilities;
using System.Xml;
using TV_Agenda_V2.Objects;
using System.Xml.Serialization;
using System.IO;
using TV_Agenda_V2.Objects.Serializable;

namespace TV_Agenda_V2
{
    /// <summary>
    /// The main window for TV Agenda V2
    /// </summary>
    public partial class MainWindow : Form
    {
        #region Variables
        private String settingsFile;
        private IShowDataSource dataSource;

        public static TVAgendaSettings Settings { get; set; }

        #region Delegates
        private delegate void ShowSearchResultsDelegate(List<Show> results);
        private delegate void UpdateShowOverviewDelegate();
        #endregion
        
        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            Settings = new TVAgendaSettings();
            dataSource = new TVRageShowDataSource(this);
            InitializeComponent();
            settingsFile = Environment.ExpandEnvironmentVariables(@"%APPDATA%\tv agenda v2 settings.xml");
            LoadXml();
        }

        /// <summary>
        /// Hides the form and displays the tray icon.
        /// </summary>
        private void ToSystemTray()
        {
            trayIcon.Visible = true;
            Hide();
        }

        #region Show handling
        /// <summary>
        /// Occures when the datasource is finished searchin for a show.
        /// </summary>
        /// <param name="asyncResult">The async result.</param>
        public void SearchShowEnd(IAsyncResult asyncResult)
        {

            List<Show> results = dataSource.EndSearchShow(asyncResult);
            if (this.InvokeRequired)
                this.Invoke(new ShowSearchResultsDelegate(ShowSearchResults), results);
            else
                ShowSearchResults(results);
        }

        /// <summary>
        /// Shows the search results.
        /// </summary>
        /// <param name="results">The results.</param>
        public void ShowSearchResults(List<Show> results)
        {
            if (results.Count < 1)
            {
                MessageBox.Show("No shows found", "Search", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            SearchResultsWindow resultsWindow = new SearchResultsWindow();
            if (resultsWindow.ShowDialog(this, results) == DialogResult.OK)
            {
                Show show = resultsWindow.SelectedShow;
                dataSource.BeginUpdateShow(show, new AsyncCallback(UpdateShowsEnd));
                dataSource.BeginUpdateEpisodes(show, new AsyncCallback(UpdateShowsEnd));
                showOverview.Shows.Add(show);
                txtSearch.SelectAll();
            }
        }

        /// <summary>
        /// Gets called when the datasource finished updating the shows
        /// </summary>
        /// <param name="result">The result.</param>
        public void UpdateShowsEnd(IAsyncResult result)
        {
            if (InvokeRequired)
                Invoke(new UpdateShowOverviewDelegate(UpdateShowOverview));
            else
                UpdateShowOverview();
        }

        /// <summary>
        /// Updates the show overview.
        /// </summary>
        public void UpdateShowOverview()
        {
            showOverview.Sort();
        }

        /// <summary>
        /// Updates the shows.
        /// </summary>
        public void UpdateShows()
        {
            dataSource.BeginUpdateShows(showOverview.Shows, new AsyncCallback(UpdateShowsEnd));
        }
        #endregion

        #region Events

        /// <summary>
        /// Handles the LinkClicked event of the lblPoweredBy control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.LinkLabelLinkClickedEventArgs"/> instance containing the event data.</param>
        private void lblPoweredBy_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process process = new System.Diagnostics.Process();
            process.StartInfo.FileName = "http://www.tvrage.com";
            process.Start();
        }

        /// <summary>
        /// Handles the Click event of the btnAddShow control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnAddShow_Click(object sender, EventArgs e)
        {
            dataSource.BeginSearchShow(txtSearch.Text, new AsyncCallback(SearchShowEnd));
        }

        /// <summary>
        /// Handles the Click event of the btnUpdate control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnUpdate_Click(object sender, EventArgs e)
        {
            UpdateShows();
        }

        /// <summary>
        /// Handles the Click event of the btnSettings control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnSettings_Click(object sender, EventArgs e)
        {
            MainWindow.Settings.LoadFromForm(this);
            SettingsForm settings = new SettingsForm();
            settings.ShowDialog(this);
            MainWindow.Settings.InitializeForm(this);
            showOverview.Sort();
        }

        /// <summary>
        /// Handles the KeyDown event of the txtSearch control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.KeyEventArgs"/> instance containing the event data.</param>
        private void txtSearch_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
                btnAddShow_Click(btnAddShow, null);
        }

        /// <summary>
        /// Handles the FormClosing event of the MainWindow control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
        private void MainWindow_FormClosing(object sender, FormClosingEventArgs e)
        {
            SaveXml(e);
        }

        /// <summary>
        /// Handles the Click event of the btnMinimizeToTray control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void btnMinimizeToTray_Click(object sender, EventArgs e)
        {
            ToSystemTray();
        }

        /// <summary>
        /// Handles the Click event of the showToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void showToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Show();
            trayIcon.Visible = false;
        }

        /// <summary>
        /// Handles the Click event of the exitToolStripMenuItem control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
            trayIcon.Visible = false;
        }

        /// <summary>
        /// Handles the MouseDoubleClick event of the trayIcon control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Forms.MouseEventArgs"/> instance containing the event data.</param>
        private void trayIcon_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            Show();
            trayIcon.Visible = false;
        }
        #endregion

        #region Save/Load settings and show list
        /// <summary>
        /// Saves the application settings and the list of shows.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.FormClosingEventArgs"/> instance containing the event data.</param>
        private void SaveXml(FormClosingEventArgs e)
        {
            TextWriter writer = null;
            try
            {
                Settings.LoadFromForm(this);
                XmlSerializer serializer = new XmlSerializer(typeof(TVAgendaSettings));
                writer = new StreamWriter(settingsFile);
                serializer.Serialize(writer, Settings);
                writer.Close();

                String xmlShowFile = Environment.ExpandEnvironmentVariables(Settings.XmlShowFile);

                serializer = new XmlSerializer(typeof(ShowList));
                writer = new StreamWriter(xmlShowFile);
                serializer.Serialize(writer, showOverview.Shows);
                writer.Close();
            }
            catch (Exception ex)
            {
                if (MessageBox.Show("Error when saving settings:\n" + ex.Message + "\nWould you like to exit anyway?", "Saving settings", MessageBoxButtons.YesNo, MessageBoxIcon.Warning) == DialogResult.No)
                    e.Cancel = true;
            }
            finally
            {
                if (writer != null)
                    writer.Close();
            }
        }

        /// <summary>
        /// Loads the application settings and the list of shows.
        /// </summary>
        private void LoadXml()
        {
            if (File.Exists(Environment.ExpandEnvironmentVariables(settingsFile)))
            {
                XmlSerializer serializer = new XmlSerializer(typeof(TVAgendaSettings));
                TextReader reader = new StreamReader(settingsFile);
                Settings = (TVAgendaSettings)serializer.Deserialize(reader);
                reader.Close();
                Settings.InitializeForm(this);
                
                String xmlShowFile = Environment.ExpandEnvironmentVariables(Settings.XmlShowFile);
                
                if (File.Exists(xmlShowFile))
                {
                    serializer = new XmlSerializer(typeof(ShowList));
                    reader = new StreamReader(xmlShowFile);
                    ShowList showList = (ShowList)serializer.Deserialize(reader);
                    reader.Close();
                    foreach (Show show in showList)
                        showOverview.Shows.Add(show);

                    showOverview.Sort();
                }
                
            }
        }

        #endregion
    }
}
